package com.shop.front.controller.pay;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.shop.domain.pay.PayDetail;
import com.shop.front.property.WxpayConstant;
import com.shop.front.service.pay.PayService;
import com.shop.front.service.store.StoreOrderService;
import com.shop.front.util.payment.WxPayUtil;
import com.shop.front.vo.store.StoreOrderUserDetailVo;
import com.shop.web.response.BaseResponse;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import static com.wechat.pay.java.core.http.Constant.*;

/**
 * @Author Administrator
 * @Date 2024/4/17 10:26
 * @Version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/wxpay")
public class WxpayController {

    @Autowired
    private StoreOrderService storeOrderService;

    @Autowired
    private PayService payService;

    /**
     * 微信公众号静默触发
     *
     * @param request
     * @param response
     */
    @RequestMapping("/callBack")
    public void callBack(HttpServletRequest request, HttpServletResponse response) {
        try {
            // 调用微信授权跳转获取openid
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            request.setCharacterEncoding("UTF-8");
            //这里要将你的授权回调地址处理一下，否则微信识别不了
            String redirect_uri = URLEncoder.encode(WxpayConstant.openIdNotifyUrl, "UTF-8");
            //简单获取openid的话参数response_type与scope与state参数固定写死即可
            StringBuffer url = new StringBuffer("https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri=" + redirect_uri +
                    "?order=123456&userId=987654&appid=" + WxpayConstant.appId + "&response_type=code&scope=snsapi_base&state=1#wechat_redirect");
            //这里千万不要使用get请求，单纯的将页面跳转到该url即可
            response.sendRedirect(url.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取微信公众号openId
     *
     * @param request
     * @return
     */
    @RequestMapping("/toPlayerInfo")
    public void toPlayerInfo(HttpServletRequest request, HttpServletResponse response) {
        try {
            //静默授权
            String get_access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                    + "appid="
                    + WxpayConstant.appId
                    + "&secret="
                    + WxpayConstant.appSecret
                    + "&code=CODE&grant_type=authorization_code";

            // 将请求、响应的编码均设置为UTF-8（防止中文乱码）
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            String order = request.getParameter("order");
            System.out.println("******************order=" + order);
            String code = request.getParameter("code");
            System.out.println("******************code=" + code);
            get_access_token_url = get_access_token_url.replace("CODE", code);
            String json = doHttpsGetJson(get_access_token_url);
            JSONObject jsonObject = JSONObject.parseObject(json);
            String openid = jsonObject.getString("openid");
            System.out.println("******************************openId=" + openid);
            request.getSession().setAttribute("openId", openid);
            request.getSession().setAttribute("orderNo", order);

            response.sendRedirect("/page/wxpay");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建订单
     *
     * @return
     */
    @RequestMapping("/createOrder")
    public BaseResponse createOrder(HttpServletRequest req) {

//        String orderNo = req.getParameter("orderNo");
        String orderNo = String.valueOf(req.getSession().getAttribute("orderNo"));
        if (StringUtils.isEmpty(orderNo) || "null".equals(orderNo)) {
            return BaseResponse.fail("订单号为空");
        }
        String openId = req.getSession().getAttribute("openId").toString();
        String filePath = WxPayUtil.uploadToLocalByUrl(WxpayConstant.privateKeyPath);
        return payService.payDetail(orderNo, openId, WxpayConstant.appId, PemUtil.loadPrivateKeyFromPath(filePath));

    }

    /**
     * 创建订单
     *
     * @return
     */
    @RequestMapping("/createOrderTwo")
    public JSONObject createOrderTwo() {

        // 初始化商户配置
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(WxpayConstant.mchId)
                        // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
                        .privateKeyFromPath(WxpayConstant.privateKeyPath)
                        .merchantSerialNumber(WxpayConstant.merchantSerialNumber)
                        .apiV3Key(WxpayConstant.apiV3Key)
                        .build();

        // 初始化服务
        JsapiService service = new JsapiService.Builder().config(config).build();
        // ... 调用接口
        try {
            PrepayRequest request = new PrepayRequest();
            request.setAppid(WxpayConstant.appId);
            request.setMchid(WxpayConstant.mchId);
            request.setDescription("商品描述");
            String orderNo = "wx_ceshi_" + System.currentTimeMillis();
            request.setOutTradeNo(orderNo);
            request.setNotifyUrl(WxpayConstant.notifyUrl);
            Amount amount = new Amount();
            // 分
            amount.setTotal(1);
            request.setAmount(amount);
            Payer payer = new Payer();
            payer.setOpenid("omTn96V1a8HRsrJh1hlJiX8N7QWs");
            request.setPayer(payer);
            PrepayResponse response = service.prepay(request);
//            String filePath = WxPayUtil.uploadToLocalByUrl(WxpayConstant.privateKeyPath);
//            WxPayUtil.WxTuneUp(response.getPrepayId(), WxpayConstant.appId, PemUtil.loadPrivateKeyFromPath(filePath));
            return WxPayUtil.WxTuneUp(response.getPrepayId(), WxpayConstant.appId, PemUtil.loadPrivateKeyFromPath(WxpayConstant.privateKeyPath));
        } catch (HttpException e) { // 发送HTTP请求失败
            // 调用e.getHttpRequest()获取请求打印日志或上报监控，更多方法见HttpException定义
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            // 调用e.getResponseBody()获取返回体打印日志或上报监控，更多方法见ServiceException定义
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            // 调用e.getMessage()获取信息打印日志或上报监控，更多方法见MalformedMessageException定义
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return new JSONObject();
    }


    /**
     * 异步回调
     *
     * @param request
     * @throws Exception
     */
    @RequestMapping(value = "xcxNotify")
    public void payNotify(HttpServletRequest request) throws Exception {
        //读取请求体的信息
        ServletInputStream inputStream = request.getInputStream();
        StringBuffer stringBuffer = new StringBuffer();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s;
        //读取回调请求体
        while ((s = bufferedReader.readLine()) != null) {
            stringBuffer.append(s);
        }
        String s1 = stringBuffer.toString();
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        String signType = request.getHeader("Wechatpay-Signature-Type");
        String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
        // 没有的话，则构造一个
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(WxpayConstant.mchId)
                .privateKeyFromPath(WxPayUtil.uploadToLocalByUrl(WxpayConstant.privateKeyPath))
                .merchantSerialNumber(WxpayConstant.merchantSerialNumber)
                .apiV3Key(WxpayConstant.apiV3Key)
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                // 若未设置signType，默认值为 WECHATPAY2-SHA256-RSA2048
                .signType(signType)
                .body(s1)
                .build();
        Transaction parse = parser.parse(requestParam, Transaction.class);
        log.info("-----------------------parse = " + parse.toString());
        try {
            System.out.println(Transaction.TradeStateEnum.SUCCESS.equals(parse.getTradeState()) && "支付成功".equals(parse.getTradeStateDesc()));
            if (Transaction.TradeStateEnum.SUCCESS.equals(parse.getTradeState()) && "支付成功".equals(parse.getTradeStateDesc())) {
                payService.payNotify(parse.getOutTradeNo(), "");
            } else {
                log.info("支付失败订单信息" + parse.getOutTradeNo());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("-----------------------回调完成-----------------------");
    }


    /**
     * 请求
     *
     * @param Url
     * @return
     */
    public static String doHttpsGetJson(String Url) {
        String message = "";
        try {
            URL urlGet = new URL(Url);
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
            http.setRequestMethod("GET");      //必须是get方式请求    24
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒28
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒29 30
            http.connect();
            InputStream is = http.getInputStream();
            int size = is.available();
            byte[] jsonBytes = new byte[size];
            is.read(jsonBytes);
            message = new String(jsonBytes, "UTF-8");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return message;
    }

}
